/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.gatech.gellinservlet.model;

import java.util.ArrayList;
import java.util.logging.FileHandler;
import java.util.logging.Filter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.io.*;

/**
 *
 * @author Tyler Powell
 */
public class UserManager extends DataManager<User> implements Serializable{
    
    public UserManager()
    {
        super();
        
        //default admin on first use
        add(new SystemAdmin("Administrator", "admin", "admin"));
        //default instructor on first use
        add(new Instructor("Robert Waters", "instructor", "instructor"));
        //default student on first use
        add(new Student("Jason Lee", "student", "student"));
    }
    
    /**
     * Creates a new system administrator
     * @param name The name of the admin
     * @param username The username they use to log in
     * @param password The password they use to log in
     * @return The instance of the system admin
     */
    public SystemAdmin createSystemAdmin(String name, String username, String password)
    {
        SystemAdmin instance = new SystemAdmin(name, username, password);
        add(instance);
        return instance;
    }
    
    /**
     * Creates a new Instructor
     * @param name The name of the instructor
     * @param username The username they use to log in
     * @param password The password they use to log in
     * @return The instance of the instructor
     */
    public Instructor createInstructor(String name, String username, String password)
    {
        Instructor instance = new Instructor(name, username, password);
        add(instance);
        return instance;
    }
    
    /**
     * Creates a new student
     * @param name The name of the student
     * @param username The username they use to log in
     * @param password The password they use to log in
     * @return The instance of the student
     */
    public Student createStudent(String name, String username, String password)
    {
        Student instance = new Student(name, username, password);
        add(instance);
        return instance;
    }
    
    /**
     * Removes the user from the database
     * @param user The user to be removed
     */
    public void remove(User user)
    {
        if(user instanceof SystemAdmin)
        {
            try
            {
                Class userClass = user.getClass();
                ArrayList<User> admins = searchOnType(userClass);
                if(admins.size() < 2)
                {
                    //TODO handle as exception properly.
                    Log.getInstance().info("Cannot delete only Admin.");
                }
                else
                {
                    super.remove(user);
                }
            } catch (InstantiationException ex)
            {
                Log.getInstance().log(Level.SEVERE, "Instantiation Exception occured in Usermanager!");
                ex.printStackTrace();
            } catch (IllegalAccessException ex)
            {
                Log.getInstance().log(Level.SEVERE, "Illegal Access Exception occured in Usermanager!");
                ex.printStackTrace();
            }
        }
        else
        {
            super.remove(user);
        }
    }
    
    /**
     * Searches for a specific type of user. 
     * @param The type of user to search for.
     * @return An array list of all users of that type
     * @throws InstantiationException
     * @throws IllegalAccessException 
     */
    public ArrayList<User> searchOnType(Class<User> E) 
            throws InstantiationException, IllegalAccessException
    {
        ArrayList<User> usersOfTypeE = new ArrayList<User>();
        Class userClass;
        
        for(User user : getDataList())
        {
            userClass = user.getClass();
            if(userClass.equals(E))
            {
                usersOfTypeE.add(user);
            }
        }
        
        return usersOfTypeE;
    }
    
    /**
     * Checks to see if the user is logged in.
     * @param username Username of the user to check
     * @param password Password of the user to check
     * @return Returns the user, if found, or null if not found
     */
    public User searchOnAuthenticate(String username, String password)
    {
        for(User user : getDataList())
        {
            String listUsername = user.getUsername();
            
            if(listUsername.equals(username))
            {
                user.incrementFailedAttempts();
                if(!user.isAccountEnabled())
                {
                    //Log.getInstance().info("User account is disabled!");
                }
                String listPassword = user.getPassword();
                if (listPassword.equals(password))
                {
                    user.resetFailedAttempts();
                    return user;
                }
            }
        }
        return null;
    }
    
    /**
      * Save this object via serialization
      * 
      * @param filename the name of the file to save to
      */
     public void save(String filename) {
         try {
             /*
              * Create the object output stream for serialization.
              * We are wrapping a FileOutputStream since we
              * want to save to disk.  You can also save to socket
              * streams or any other kind of stream.
              */
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename));
            
            /*
             * The only real call we need.  The stream buffers the output and reuses
             * data, so if you are serializing very frequently, then the object values might
             * not actually change because the old serialized object is being reused.
             * 
             * To fix this you can try writeUnshared() or you can reset the stream.
             * out.reset();
             */
            out.writeObject(this.getDataList());
            //out.writeObject(this.getDataList()); //this writes out the members, so we know that works
        } catch (FileNotFoundException e) {
            Log.getInstance().log(Level.SEVERE, "Save file not found: " + filename, e);
        } catch (IOException e) {
            Log.getInstance().log(Level.SEVERE, "General IO Error on saving: " + filename, e);
        }
         
     }
     
     /**
     * This is an example of a factory method
     * We call this static method to create an
     * instance of UserManager from a serialized file.
     *
     * @param filename the name of the file to use
     * @return an instance of UserManager initialized from a file.
     */
     public void getFromFile(String filename) {
         ArrayList c = null;
         try {
             /*
              * Create the input stream.  Since we want to read from the disk,
              * we wrap a file stream.
              */
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
            /*
             * Now we can read the entire company in with only one call
             */
            c = (ArrayList) in.readObject();
            this.setDataList(c);

        } catch (FileNotFoundException e) {
            Log.getInstance().log(Level.SEVERE, "Load file not found: " + filename, e);
        } catch (IOException e) {
            Log.getInstance().log(Level.SEVERE, "General IO Error on loading: " + filename, e);
        } catch (ClassNotFoundException e) {
            Log.getInstance().log(Level.SEVERE, "Company class not found on loading: " + filename, e);
        }
        
     }
    
}
